import 'dart:convert';

import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:get/get.dart' as GET;
import 'package:get/get_core/src/get_main.dart';

import 'package:get_storage/get_storage.dart';
import 'package:uuid/uuid.dart';
import 'package:wk_robot2/app/event/MsgContentEvent.dart';
import 'package:wk_robot2/app/event/WkEventListener.dart';
import 'package:wk_robot2/app/storage/StorageManager.dart';
import 'package:wk_robot2/app/utils/CommonUtil.dart';
import 'package:wk_robot2/app/utils/NetWorkUtil.dart';
import 'package:wk_robot2/app/widget/CommonWidgets.dart';
import '../const/AppConst.dart';
import '../event/DataCallBack.dart';
import '../logger/Logger.dart';
import '../routes/app_pages.dart';
import '../widget/tips.dart';



class NetWorkManager {
  // 开发环境
  // static String HOST_IP = "zxlab-dev.ubtrobot.com";

  //对外测试环境.
  static String HOST_IP = dotenv.env['HOST_IP'] ?? 'zxlab-dev.ubtrobot.com';
  //https://zxcnagent.ubtrobot.com

  static String APIPort1 = HOST_IP + "/";

  //业务服务器地址.
  static String mServerHost = "https://" + APIPort1;
  // localhost
  //static String mServerHost = "http://10.10.17.88:9020/";

  /// 单例对象
  static NetWorkManager? _instance;

  /// 内部构造方法，可避免外部暴露构造函数，进行实例化
  NetWorkManager._internal();

  /// 工厂构造方法，这里使用命名构造函数方式进行声明
  factory NetWorkManager.getInstance() => _getInstance();

  // 网络进度条.
  static SizedBox? processSizeBox;

  /// 获取单例内部方法
  static _getInstance() {
    // 只能有一个实例
    if (_instance == null) {
      _instance = NetWorkManager._internal();
      processSizeBox = SizedBox(
        height: 100,
        width: 100,
        child: CircularProgressIndicator(
          backgroundColor: Colors.grey[200],
          valueColor: const AlwaysStoppedAnimation(Colors.blue),
        ),
      );
    }
    return _instance;
  }

  void clearCache(DataCallBack dataCallBack) async {
    GetStorage().erase();
    dataCallBack.businessCallBack??(true);
  }

  // 业务请求接口.
  void requestBussiness(
      String url,
      Map<String, dynamic> data,
      String method,
      DataCallBack dataCallBack, {bool showLoading = false}) async {

     //做权限检查.
     bool isNetWork = await NetWorkUtil.checkNetWorkIsAvailable();
     if (!isNetWork) {
       Tips.showToast('网络不可用.');
       return;
     }

    var dio = Dio(BaseOptions(
      baseUrl: mServerHost,
      contentType:"application/json"
    ));

    dio.interceptors.add(InterceptorsWrapper(
           onRequest: (requestOptions, handler) {
               logger.info('REQUEST[${requestOptions.method}] => PATH: ${requestOptions.path}, params: ${requestOptions.data}');

              if(StorageManager.getStorage().hasData(AppConst.storage_key_login_token)) {
                  requestOptions.headers[AppConst.AUTHORIZATION] = StorageManager.getStorage().read(AppConst.storage_key_login_token)['token'];
              }

              requestOptions.headers['X-UBT-AppId'] = AppConst.X_UBT_APPID;
              requestOptions.headers['X-UBT-DeviceId'] = CommonUtil.getDeviceId();
              requestOptions.headers['X-UBT-Sign'] = toSign();
              requestOptions.headers['product'] = "12012";

              return handler.next(requestOptions); //continue
           },
           onResponse: (response, handler) {

                Map<String, dynamic> data = response.data;
                logger.info('response data: ${json.encode(data)}');

                if (showLoading) {
                  Tips.dismissLoading();
                }

                if (data["code"] == 0) { //成功.
                   if (data["data"] != null) {
                     dataCallBack.businessCallBack!(data["data"]);
                   } else {
                     dataCallBack.businessCallBack!(null);
                   }

                   return handler.next(response); // continue

                } else if (data["code"] == 401) { //未授权或授权过期.
                  //token过期,重新登陆.
                 /* CommonWidgets.showSingleBtnDialog(Get.context!, '安全提醒', '账号', WkEventListener(
                    onClick: (v) {
                      clearCache(DataCallBack(businessCallBack: (data) {
                        GET.Get.offAllNamed(Routes.LOGIN);
                      }));
                    }
                  ));*/



                } else if (data["code"] == -3 &&
                    data["message"] != null &&
                    data["message"].toString().contains("token")) { //登陆过期.
                    //token失效，跳转到登录界面
                    clearCache(DataCallBack(businessCallBack: (data) {
                      
                    }));
                } else {
                   if (data["message"] != null) { // 系统错误默认处理.

                     if (dataCallBack!.errorCallBack == null) {
                       Tips.showToast(data["message"]);
                     } else {
                       dataCallBack!.errorCallBack!(data["message"]);
                     }


                   }

                    // return handler.next(response);
                }
           },
           onError: (DioException exception, handler) {
                if (showLoading) {
                   Tips.dismissLoading();
                }

                if (exception.response != null &&  exception.response!.statusCode == 401) {
                   //权限失效或未登录,则跳转登录页面.

                  // Get.offAllNamed(Routes.LOGIN);
                  eventBus.fire(ProductContentEvent(ACCOUNT_TOKEN_UNVAILABLE));

                } else {
                  if(dataCallBack.errorCallBack == null) {
                    Tips.showToast('服务器暂时失联.');
                    // Get.offAllNamed(Routes.LOGIN);
                  } else {
                    dataCallBack.errorCallBack??("Server errors.");
                  }
                }


                return handler.next(exception); //continue
           }
    ));

    //dio设置.
    dio.interceptors.add(LogInterceptor(requestBody: true, responseBody: true));

    // print("请求参数: $data");

    if (showLoading) {
       Tips.showLoading();
    }

    dio.request<Map<String, dynamic>>(url,
            data: data,
            queryParameters: method == NetWorkManager.methodGET ? data : {},
            options: Options(method: method));


   /*if (showLoading) {
     Tips.dismissLoading();
   }*/

   // dataCallBack.businessCallBack!(response.data!["data"] != null ? response.data!["data"] : response.data);

  }


  // uploadFile.
  void uploadFile (
      String url,
      Object? data,
      String method,
      DataCallBack dataCallBack)  {

    var dio = Dio(BaseOptions(
        baseUrl: mServerHost,
        contentType:"application/json"
    ));

    // dio设置.
    // dio.interceptors.add(LogInterceptor(responseBody: true));

    // print("请求参数: $data");
    logger.info("请求的URL为:" + url);

    Tips.showLoading();
    dio.request<Map<String, dynamic>>(url,
        data: data, options: Options(method: method)).then((response)  {

      Tips.dismissLoading();
      dataCallBack.businessCallBack!(response.data!["data"] != null ?
      response.data!["data"] : response.data);
    }
    );

  }


  // downloadFile.
  void downloadFile (
      String url, String savePath, ProgressCallback progressCallback, CancelToken cancelToken)  {

    var dio = Dio(BaseOptions(
        baseUrl: mServerHost,
     
        contentType:"application/json"
    ));

    logger.info("下载URL为:" + url);

    try {
      dio.download(url, savePath,onReceiveProgress:  progressCallback,
          cancelToken: cancelToken,
          options: Options(
            followRedirects: false,
            validateStatus: (status) {
              return status! < 500;
            },
          )
      ).then((value)  {
        logger.info("文件URL为:${url}下载成功.");
      });
    } catch (e) {
        logger.info('Error during file download: $e');
    }

  }


  String toSign() {
    String deviceId = CommonUtil.getDeviceId();
    int signTimestamp = 0;
    if(StorageManager.getStorage().hasData(AppConst.storage_server_system_timestamp)) {
        int system_timestamp = StorageManager.getStorage().read(AppConst.storage_server_system_timestamp);
        int local_record_timestamp = StorageManager.getStorage().read(AppConst.storage_local_system_timestamp);
        //offset of system timestamp;
        int offsetTime = DateTime.now().millisecondsSinceEpoch - local_record_timestamp;
        system_timestamp = system_timestamp + offsetTime;

        signTimestamp = system_timestamp;
    } else {
      signTimestamp = DateTime.now().millisecondsSinceEpoch;
    }

    return  sign(deviceId,signTimestamp,Uuid().v4().substring(0,8));
  }



  String sign(String deviceId, int timestamp, String prefixUUID8) {
    logger.info('deviceId: $deviceId, timestamp:: ${timestamp.toString()}, prefixUuid:$prefixUUID8');

     return md5(timestamp.toString() + AppConst.SIGN_APP_KEY + prefixUUID8 + deviceId)+' '+ timestamp.toString() + ' ' + prefixUUID8 +' '+'v2';
  }


  String md5(String signInfo) {

     return CommonUtil.calculateMD5(signInfo).padLeft(32,'0');

  }



  static String methodPOST = "POST";
  static String methodGET = "GET";
  static String methodDELETE = "DELETE";
  /// *****业务接口 Begin *********/
  static String GET_MSG_VALIDATE_CODE = "/common-user-server/user/captcha/security";
  static String USER_LOGINING = "/common-user-server/user/login/cellphone/cv2";
  static String TO_REFRESH_TOKEN = "/common-user-server/user/token/refreshToken";


  static String GET_MY_ROBOT_LIST = "/wukong2-server/relation/getRobots";

  static String BIND_ROBOT_TO_USER = "/wukong2-server/relation/registerRobot";
  static String UAGENT_TOKEN_CREATE = '/wukong2-server/uagent/token/create';
  static String BIND_CONFIG_ROBOTE_UNBIND = '/wukong2-server/relation/unbind';
  // 敏感词检测
  static String SENSETIVE_CHECK = "/wukong2-server/skill/sensitive/check";

  static String ROBOT_GET_BINDUSERS = '/wukong2-server/relation/getBindUsers';

  // 动作广场数据.
  static String ACTIONSQUARE_ALL = '/wukong2-server/actionsquare/all';


  //注销账号
  static String DISMISS_USER_ACCOUNT = '/common-user-server/user';
  /******* 业务接口 End *********/




}

enum PostParamPosition {
  //请求参数放在消息头的参数中
  query,
  // 请求参数放在消息体中
  body
}
